Час 13 - Анимације више објеката, oчитавање миша и тастатуре¶
Анимације више објеката¶
Аутомобил и авион¶
Напиши програм који приказује анимацију авиона који се креће по
небу и аутомобила који се креће по земљи, при чему је брзина авиона
два пута већа него аутомобила. Када неко возило изађе на десном
крају екрана, појављује се поново на левом. Поново можеш употребити
слике auto.png
и avion.png
.


Задатак веома једноставно можемо решити тако што практично два пута поновимо кôд који смо написали у програму у ком смо вршили симулацију аутомобила. Понављање истог или сличног кода више пута је иначе веома лоша пракса и касније ћемо видети начине да се то избегне када се ради са више објеката, али с обзиром на то да се овде кôд понавља само једном, то можемо толерисати.
import math
import pygame as pg
import pygamebg
(sirina, visina) = (500, 300) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Ауто и авион")
avion_slika = pg.image.load("avion.png")
(avion_x, avion_y) = (0, ???)
auto_slika = pg.image.load("auto.png")
(auto_x, auto_y) = (0, ???)
def crtaj():
prozor.fill(pg.Color("white"))
prozor.blit(avion_slika, (avion_x, avion_y)) # crtamo avion
??? # crtamo auto
def novi_frejm():
global avion_x, avion_y, auto_x, auto_y
# pomeramo avion
avion_x += 2
if avion_x > sirina:
avion_x = - avion_slika.get_width()
# pomeramo auto
???
crtaj()
pygamebg.frame_loop(100, novi_frejm)
(auto_avion)
Две лоптице¶
Напиши програм који приказује црвену и плаву лоптицу које се крећу по екрану, одбијају од ивица и одбијају међусобно (једноставности ради претпостави да приликом сударе две лоптице једноставно размене векторе кретања).
Поново независно вршимо анимацију два различита објекта. Кључна новина је то што се објекти могу међусобно сударати. Два круга се сударају (пресецају) ако и само ако је растојање њихових центара веће од збира њихових полупречника. Растојање рачунамо на уобичајени начин, Питагорином теоремом. Ако се лоптице сударају, размењујемо им помераје по x и помераје по y оси (векторе брзине).
import math
import pygame as pg
import pygamebg
(sirina, visina) = (300, 200) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Две лоптице")
r = 20
(x1, y1) = (r, r)
(dx1, dy1) = (1, 1)
(x2, y2) = (sirina - r, visina - r)
(dx2, dy2) = (-1, -1)
def crtaj():
prozor.fill(pg.Color("white"))
pg.draw.circle(prozor, pg.Color("red"), (x1, y1), r)
pg.draw.circle(prozor, pg.Color("blue"), (x2, y2), r)
# rastojanje između centara loptica
def rastojanje():
return math.sqrt((x1-x2)**2 + (y1-y2)**2)
# provera da li se dve loptice sudaraju
def sudar():
return rastojanje() <= 2*r
def novi_frejm():
global x1, y1, x2, y2, dx1, dy1, dx2, dy2
# pomeramo prvu lopticu i proveravamo sudar sa ivicama prozora
x1 += dx1
y1 += dy1
if x1 - r < 0 or x1 + r > sirina:
dx1 = -dx1
if y1 - r < 0 or y1 + r > visina:
dy1 = -dy1
# pomeramo drugu lopticu i proveravamo sudar sa ivicama prozora
???
# ispitujemo sudar dve loptice
if sudar():
(dx1, dy1, dx2, dy2) = (dx2, dy2, dx1, dy1)
crtaj()
pygamebg.frame_loop(100, novi_frejm)
(dve_loptice)
Пахуљице¶
Напиши програм који приказује анимацију пахуља које падају са врха
на дно екрана. Можеш употребити слику pahulja.png
. Када пахуље
падну на дно екрана, нове крећу да падају са врха.

Центре пахуљица можемо памтити у листи парова. Један начин да реализујемо померање пахуљица је тај да од текуће листе направимо нову у којој ће x координате свих елемената бити неизмењене, а у којој ће y координате бити увећане за 1. При том, из листе можемо избацити пахуље које су пале испод дна екрана (којима је y координата врха већа од висине прозора) и за сваку пахуљу која испадне у листу додамо нову пахуљу (њој координате одређујемо насумично, тако да се по ширини налази унутар прозора, а да по висини креће да пада из појаса изнад екрана који је широк једну петину екрана).
import random
import pygame as pg
import pygamebg
(sirina, visina) = (800, 400) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Пахуљице")
pahulja_slika = pg.image.load("pahulja.png") # slika pahuljice
broj_pahulja = 10 # ukupan broj pahuljica
# nasumično generišemo centre pahuljica
centri_pahulja = [(???, ???)
for i in range(???)]
def crtaj():
prozor.fill(pg.Color("white")) # bojimo pozadinu u belo
dim = pahulja_slika.get_width() # dimenzije slike pahulje
for (x, y) in ???: # crtamo sve pahulje
prozor.blit(pahulja_slika, (???, ???))
def novi_frejm():
global centri_pahulja
# pomeramo pahulje i u listi ostavljamo samo one koje još nisu ispale
centri_pahulja = [(x, y+1) for (x, y) in centri_pahulja if ???]
# popunjavamo prazna mesta novih pahuljama koje kreću da padaju iznad vrha ekrana
while len(centri_pahulja) < ???:
centri_pahulja.append((random.randint(0, sirina),
random.randint(-visina // 5, 0)))
crtaj()
pygamebg.frame_loop(50, novi_frejm)
(pahuljice)
Очитавање миша и тастатуре¶
Корисник интеракцију са програмом обично врши мишем или тастатуром. Напреднији облици интеракције подразумевају реаговање на догађаје и њих ћемо описати у наредном поглављу посвећеном догађајима. Ипак наше анимације можемо веома једноставно учинити интересантнијим помоћу веома једноставне функционалности очитавања стања миша и тастатуре (за шта нам нису потребни догађаји).
Функција
pg.mouse.get_pos()
враћа уређени пар координата тачке на којој се тренутно налази показивач миша.Функција
pg.mouse.get_pressed()
враћа торку од три елемента (уређену тројку), који се користе као логичке вредности. Елементи торке редом одговарају левом, средњем и десном тастеру миша. ВредностTrue
означава да је тастер притиснут, аFalse
да није. Тако се, на пример, условомif pg.mouse.get_pressed()[0]:
могу оградити наредбе које се извршавају само ако је притиснут леви тастер миша.Функција
pg.key.get_pressed()
враћа торку чији се елементи користе као логичке вредности, а показују за сваки тастер на тастатури да ли је он тренутно притиснут или не. Пошто је тастера пуно, за њихово очитавање се користе именоване константе. Константеpg.K_LEFT
,pg.K_RIGHT
,pg.K_UP
,pg.K_DOWN
одговарају тастерима са стрелицама, размаку одговара константаpg.K_SPACE
, док тастерима слова, на пример a, b, c, одговарају константеpg.K_a
,pg.K_b
,pg.K_c
итд. Тако се, на пример, условомif pg.key.get_pressed()[pg.K_SPACE]:
могу оградити наредбе које се извршавају само ако је притиснут тастер за размак.
У овом приручнику нећемо пуно инсистирати на коришћењу ове технике, јер ћемо детаљније обрадити механизам догађајај. Прикажимо само неколико једноставних примера.
Анимирани лептир кога померамо мишем¶
Напиши програм који приказује анимираног лептира који лети по
екрану и чији се центар налази увек тачно изнад показивача миша.
За анимацију можеш употребити слике leptir1.png
и
leptir2.png
.


import random, math
import pygame as pg
import pygamebg
(sirina, visina) = (400, 400) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Лептир прати миша")
# učitavamo dve slike leptira u listu
leptir_slike = []
for i in range(2):
naziv_slike = "leptir" + str(???) + ".png"
leptir_slike.append(???)
broj_frejma = 0 # redni broj tekućeg frejma
def crtaj():
prozor.fill(pg.Color("white")) # bojimo pozadinu u belo
(mis_x, mis_y) = pg.mouse.get_pos() # koordinate miša
broj_slike = (broj_frejma // 10) % len(leptir_slike) # redni broj slike - svaka se slika prikazuje 10 frejmova
slika = leptir_slike[broj_slike] # slika koja se prikazuje
slika_sirina = ??? # prikazujemo sliku centrirano
slika_visina = ???
(x, y) = (???, ???)
prozor.blit(slika, (x, y))
def novi_frejm():
global broj_frejma
??? # uvećavamo redni broj frejma
crtaj()
pygamebg.frame_loop(50, novi_frejm)
(animirani_leptir)
Лоптица која прати миша¶
Напиши програм који приказује лоптицу која се увек полако креће ка тренутној позицији миша.
У програму ћемо памтити текућу позицију лоптице. Кључно питање је како одредити позицију лоптице у наредном фрејму. Нека тачка A представља текућу позицију центра лоптице, нека тачка B представља текућу позицију показивача миша и нека тачка X представља нову позицију центра лоптице. Пошто се центар помера из тачке A у тачку X лоптица у једном фрејму пређе пут једнак растојању између те две тачке. Обележимо ту вредност са v (ако хоћемо да се лоптица креће глатко, број фрејмова у секунди треба да буде већи, а то треба да буде нека мала вредност). Поставља се питање колико по хоризонтали и колико по вертикали треба да се помери лоптица. Троуглови AXxX и ACB су слични. Зато се дужине AXx и XxX које представљају хоризонтално и вертикално померање могу израчунати на основу дужине AX која је једнака v, дужине AB која се може израчунати Питагорином теоремом као растојање између тачке А и B чије су нам координате познате, дужине AC која је једнака разлици између x координата тачака A и B и дужне BC која је разлика између њихових y координата. Важи да је AXx:AX=AC:AB, као и да је XXx:AX=BC:AB одакле се израчунавају координате непознате тачке X.

import random, math
import pygame as pg
import pygamebg
(sirina, visina) = (250, 250) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Лоптица прати миша")
# rastojanje između dve date tačke (zadate parovima koordinata)
def rastojanje(A, B):
(xa, ya) = A
(xb, yb) = ???
return math.sqrt(???**2 + ???**2)
(x, y) = (???, ???) # pozicija loptice - inicijalno u centru prozora
def crtaj():
# crtamo zelenu lopticu na beloj pozadini
prozor.fill(???)
pg.draw.circle(prozor, ???, ???, 10)
def novi_frejm():
global x, y
(xm, ym) = ??? # koordinate pozicije miša
d = rastojanje((x, y), (xm, ym)) # rastojanje tačke od miša
v = 2 # brzina kretanja loptice
if d < v: # ako je loptica dovoljno blizu miša pomera
(x, y) = ??? # pomera se tačno na poziciju miša
else: # u suprotnom
x = x + v * (xm - x) / d # pomera se malo u smeru ka mišu
???
crtaj()
pygamebg.frame_loop(50, novi_frejm)
(pratim_misa)